using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using SharedContent;

namespace GlobalGameJam
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Player : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public List<Rectangle> hitbox;
        //public Texture2D    sprite;

        public SpriteManager sprite;
        public Sprite todraw;
        private float _timer;
        public Vector2 position;
        public Vector2 max;
        public int direction;
        public float speed;
        public float slowTime;
        public InputManager inputManager;
        private GameplayScreen _game;
        private bool hasChangedState;
        public int scalePower;
        public Player(GameplayScreen game)
            : base(game)
        {
            this.scalePower = 20;
            this._game = game;
            //this.sprite = null;
            this.sprite = new SpriteManager();

            this.position = Vector2.Zero;
            this.max = Vector2.Zero;
            this.direction = 0;
            this.speed = (this.direction == 0 || this.direction == 1) ? this.max.X / 150 : this.max.Y / 100;
            this.hitbox = new List<Rectangle>();
            this.slowTime = 0f;
            // TODO: Construct any child components here
        }

        public void LoadContent(ContentManager c, string assetName)
        {
            this.inputManager = c.Load<InputManager>(assetName);
            sprite.LoadContent(c, "spriteboard1");
        }

        public void slow()
        {

            if (this.slowTime != 0)
                return;
            this.slowTime = 3000;
            this.speed /= 2;
        }

        public void checkSlow(GameTime gametime)
        {
            if (this.slowTime == 0)
                return;
            this.slowTime -= gametime.ElapsedGameTime.Milliseconds;
            if (this.slowTime <= 0)
            {
                this.slowTime = 0;
                this.speed *= 2;
            }
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public virtual void Initialize(Texture2D sprite, Vector2 position, Vector2 max)
        {
            // TODO: Add your initialization code here
            //this.sprite = sprite;
            //this.sprite = new SpriteManager();
            this.position = position;
            this.position = new Vector2(600, 400);
            this.max = max;
            this.direction = 0;
            this.speed = (this.direction == 0 || this.direction == 1) ? this.max.X / 150 : this.max.Y / 100;
            this.hitbox = new List<Rectangle>();
            this.hitbox.Add(new Rectangle((int)this.position.X, (int)this.position.Y, 75, 75));
            this._timer = 0;
        }
        public void bite()
        {
            this.sprite._isBite = true;
            hasChangedState = true;
        }
        public void jump()
        {
            float mvt = 0;
            this.sprite._isJump = true;
            Vector2 pos = this.position;
            if (this.direction == 0 || this.direction == 1)
            {
                this.position += new Vector2(0, -25);
                mvt += 25;
            }
            else
            {
                this.position += new Vector2(0, -this.speed);
                mvt += this.speed;
            }
            UpdateHitbox();
            if (_game.collisionManager.thereIsObstacle(this) && !_game.collisionManager.tryToEscalade(this))
                this.position = pos;
            else
            {
                this.position = pos;
                _game.collisionManager.allDown(mvt);
                hasChangedState = true;
            }
        }
        public void down()
        {
            float mvt = 0;
            Vector2 pos = this.position;
            if (this.direction == 0 || this.direction == 1)
            {
                mvt += 25;
                this.position += new Vector2(0, 25);
            }
            else
            {
                mvt += (int)this.speed;
                this.position += new Vector2(0, this.speed);
            }
            UpdateHitbox();
            if (_game.collisionManager.thereIsObstacle(this) && !_game.collisionManager.tryToEscalade(this))
                this.position = pos;
            else
            {
                this.position = pos;
                _game.collisionManager.allUp(mvt);
                hasChangedState = true;
            }
        }
        public void right()
        {
            this.sprite._isRight = true;
            Vector2 pos = this.position;
            if (this.direction == 0 || this.direction == 1)
                this.position += new Vector2(this.speed, 0);
            else
                this.position += new Vector2(25, 0);
            UpdateHitbox();
            if (_game.collisionManager.thereIsObstacle(this) && !_game.collisionManager.tryToEscalade(this))
                this.position = pos;
            else
            {
                this.position = pos;
                this._game.collisionManager.allLeft(this.speed);
                hasChangedState = true;
            }
        }
        public void left()
        {
            this.sprite._isRight = false;
            Vector2 pos = this.position;
            if (this.direction == 0 || this.direction == 1)
                this.position += new Vector2(-this.speed, 0);
            else
                this.position += new Vector2(-250, 0);
            UpdateHitbox();
            if (_game.collisionManager.thereIsObstacle(this) && !_game.collisionManager.tryToEscalade(this))
                this.position = pos;
            else
            {
                this.position = pos;
                this._game.collisionManager.allRight((int)this.speed);
                hasChangedState = true;
            }
        }
        public void center()
        {
            if (this.position.X < 600)
                _game.collisionManager.allRight(600 - this.position.X);
            else if (this.position.X > 600)
                _game.collisionManager.allLeft(this.position.X - 600);
            if (this.position.Y < 400)
                _game.collisionManager.allDown(400 - this.position.Y);
            else if (this.position.Y > 400)
                _game.collisionManager.allUp(this.position.Y - 400);
            this.position.X = 600;
            this.position.Y = 400;
        }
        public void quit()
        {
            System.Environment.Exit(1);
        }

        public void UpdateHitbox()
        {
            this.hitbox.Clear();
            //            this.hitbox.Add(new Rectangle((int)this.position.X, (int)this.position.Y, this.sprite.Width, this.sprite.Height));
            this.hitbox.Add(new Rectangle((int)this.position.X, (int)this.position.Y, this.todraw.rec.Width, this.todraw.rec.Height));

        }
        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {

            hasChangedState = false;
            this.todraw = this.sprite.getImage();
            this.UpdateHitbox();
            Vector2 pos = this.position;
            if (_game.collisionManager.thereIsObstacle(this))
            {
                if (!_game.collisionManager.tryToEscalade(this))
                    this.position = pos;
            }

            KeyboardState state = Keyboard.GetState();
            if (this.slowTime == 0)
                this.speed = (this.direction == 0 || this.direction == 1) ? this.max.X / 150 : this.max.Y / 100;
            GamePadState stateGamePad = GamePad.GetState(PlayerIndex.One);
            Dictionary<Action, string> methods = new Dictionary<Action, string>();
            methods.Add(new Action(jump), "jump");
            methods.Add(new Action(down), "down");
            methods.Add(new Action(right), "right");
            methods.Add(new Action(left), "left");
            methods.Add(new Action(center), "center");
            methods.Add(new Action(bite), "bite");

            this.UpdateHitbox();
            foreach (KeyValuePair<Action, string> p in methods)
            {
                bool triggered = false;
                // Gestion des evenements
                List<Keys> keysToAct = inputManager.getKeysFor(p.Value);
                List<Buttons> buttonsToAct = inputManager.getButtonsFor(p.Value);
                foreach (Keys k in keysToAct)
                    if (state.IsKeyDown(k))
                    {
                        p.Key();
                        triggered = true;
                    }
                if (!triggered)
                    foreach (Buttons b in buttonsToAct)
                        if (stateGamePad.IsButtonDown(b))
                        {
                            p.Key();
                            break;
                        }
            }
            this.position.X = (this.position.X < 0) ? (0) : (this.position.X);
            //this.position.X = (this.position.X > this.max.X - this.sprite.Width) ? (this.max.X - this.sprite.Width) : (this.position.X);
            this.position.X = (this.position.X > this.max.X - 75) ? (this.max.X - 75) : (this.position.X);

            this.position.Y = (this.position.Y < 0) ? (0) : (this.position.Y);
            //this.position.Y = (this.position.Y > this.max.Y - this.sprite.Height) ? (this.max.Y - this.sprite.Height) : (this.position.Y);
            this.position.Y = (this.position.Y > this.max.Y - 75) ? (this.max.Y - 75) : (this.position.Y);
            if (!hasChangedState)
                this.sprite.setState(SpriteManager.State.StandUp);
            _timer += gameTime.ElapsedGameTime.Milliseconds;
            if (_timer > 150)
            {
                _timer = 0;
              this.sprite.nextFrame();
            }
            if (!hasChangedState)
            {
                if (this.sprite._isRight == true)
                    this.sprite.setState(SpriteManager.State.StandUp);
                else
                    this.sprite.setState(SpriteManager.State.StandUpLeft);
            }
            if (this.sprite._isJump == true && hasChangedState == true /* && _fall == false*/)
            {
                if (this.sprite._isRight == true && this.sprite._state != SpriteManager.State.JumpRight)
                    this.sprite.setState(SpriteManager.State.JumpRight);
                else if (this.sprite._isRight == false && this.sprite._state != SpriteManager.State.JumpLeft)
                    this.sprite.setState(SpriteManager.State.JumpLeft);
            }
            else if (this.sprite._isJump == false && hasChangedState == true /*&& _fall == false*/)
            {
                if (this.sprite._isRight == true && this.sprite._state != SpriteManager.State.RunRight)
                    this.sprite.setState(SpriteManager.State.RunRight);
                else if (this.sprite._isRight == false && this.sprite._state != SpriteManager.State.RunLeft)
                    this.sprite.setState(SpriteManager.State.RunLeft);
                if (this.sprite._isBite == true)
                {
                    if (this.sprite._isRight == true && this.sprite._state != SpriteManager.State.BiteRight)
                        this.sprite.setState(SpriteManager.State.BiteRight);
                    else if (this.sprite._isRight == false && this.sprite._state != SpriteManager.State.BiteLeft)
                        this.sprite.setState(SpriteManager.State.BiteLeft);
                }
            }

            //else if (/* && _fall == true*/)
            //{
            //if (this.sprite._isRight == true && this.sprite._state != SpriteManager.State.FallRight)
            //   this.sprite.setState(SpriteManager.State.FallRight);
            //else if (this.sprite._isRight == false && this.sprite._state != SpriteManager.State.FallLeft)
            //   this.sprite.setState(SpriteManager.State.FallLeft);
            // }
            this.sprite._isJump = false;
            this.sprite._isBite = false;
            hasChangedState = false;
            this.todraw = this.sprite.getImage();
            this.UpdateHitbox();
            // TODO: Add your update code here
            base.Update(gameTime);
        }

        public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
            todraw = sprite.getImage();
            //spriteBatch.Draw(this.sprite, this.position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1.0f);
            if (this.direction == 1)
                spriteBatch.Draw(sprite._sprite, this.position, todraw.rec, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.FlipVertically, 1.0f);
            else
                spriteBatch.Draw(sprite._sprite, this.position, todraw.rec, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None , 1.0f);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

